// 延迟函数
const delay = (interval) => {
  typeof interval !== 'number' ? interval = 1000  : null
  return new Promise(resolve => {
    setTimeout(() => {
      resolve()
    }, interval);
  })
};
// 单一文件上传 formData
(function () {
  let upload1 = document.querySelector('#upload1'),
    upload_inp = upload1.querySelector('.upload_inp'),
    upload_btn_select = upload1.querySelector('.upload_btn.select'),
    upload_btn_upload = upload1.querySelector('.upload_btn.upload'),
    upload_tip = upload1.querySelector('.upload_tip'),
    upload_list = upload1.querySelector('.upload_list');

  let _file = null

  // 点击选择文件按钮，触发上传文件input输入框
  upload_btn_select.addEventListener('click', function() {
    if (upload_btn_select.classList.contains('disabled')) {
      return
    }
    upload_inp.click()
  })

  // 监听用户选择文件的操作，并获取用户选择的文件
  upload_inp.addEventListener('change', function() {
    const file = upload_inp.files[0]
    if (!file) return
    // 限制文件上传的格式
    if(!/PNG|JPG|JPEG/i.test(file.type)) {
      alert('只能上传PNG/JPG/JPEG格式的图片~')
      return
    }
    // 限制文件大小
    if (file.size > 2 * 1024 * 1024) {
      alert('图片大小不能超过2M~')
      return
    }
    // 显示上传的文件
    upload_tip.style.display = 'none'
    upload_list.style.display = 'block'
    upload_list.innerHTML = `<li>
      <span>文件：${file.name}</span>
      <span><em>移除</em></span>
    </li>
    `
    _file = file
  })

  const clearHandle = () => {
    upload_tip.style.display = 'block'
    upload_list.style.display = 'none'
    upload_list.innerHTML = ``
    _file = null
  }

  // 移除选择的图片
  upload_list.addEventListener('click', function(ev) {
    let target = ev.target
    if (target.tagName === 'EM') {
      clearHandle()
    }
  })

  const handleDisable = (flag) => {
    if (flag) {
      upload_btn_select.classList.add('disabled')
      upload_btn_upload.classList.add('disabled')
      return
    }
    upload_btn_select.classList.remove('disabled')
    upload_btn_upload.classList.remove('disabled')
  }

  // 上传到服务器
  upload_btn_upload.addEventListener('click', function() {
    if (!_file) {
      alert('请选择上传的文件')
      return
    }
    handleDisable(true)

    // 上传 FormData
    let formData = new FormData()
    formData.append('file', _file)
    formData.append('filename', _file.name)

    instance.post('/upload_single', formData)
    .then(data => {
      if (+data.code === 0) {
        alert(`文件上传成功，可以使用 ${data.servicePath} 访问这个资源~`)
        return
      }
      return Promise.reject(data.codeText)
    }).catch(reason => {
      alert('文件上传失败，清稍后重试~')
    }).finally(() => {
      handleDisable(false)
      clearHandle()
    })
  })


})();

// 单一文件上传 base64
(function () {
  let upload2 = document.querySelector('#upload2'),
    upload_inp = upload2.querySelector('.upload_inp'),
    upload_btn_select = upload2.querySelector('.upload_btn.select');

  const checkIsDisable = (element) => {
    const classlist = element.classList
    return classlist.contains('disabled')
  }

  // 点击选择文件按钮，触发上传文件input输入框
  upload_btn_select.addEventListener('click', function() {
    checkIsDisable(this)
    upload_inp.click()
  })

  // 监听用户选择文件的操作，并获取用户选择的文件
  upload_inp.addEventListener('change', function() {
    const file = upload_inp.files[0]
    if (!file) return
    // 限制文件上传的格式
    if(!/PNG|JPG|JPEG/i.test(file.type)) {
      alert('只能上传PNG/JPG/JPEG格式的图片~')
      return
    }
    // 限制文件大小
    if (file.size > 2 * 1024 * 1024) {
      alert('图片大小不能超过2M~')
      return
    }
    upload_btn_select.classList.add('disabled')
    upload(file)

  })

  // todo 上传
  const upload = async (file) => {
    const base64 = await readFileToBase64(file)
    try {
      const data = await instance.post('/upload_single_base64', {
        file: encodeURIComponent(base64), // 防止传输的过程中出现乱码
        filename: file.name
      }, {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        }
      })
      if (+data.code === 0) {
        alert(`文件上传成功，可以使用 ${data.servicePath} 访问这个资源~`)
        return
      }
      throw data.codeText
    } catch (error) {
      console.log(error);
      alert(error)
    }finally {
      upload_btn_select.classList.remove('disabled')
    }
  }
  // 把选择的文件读取为base64
  const readFileToBase64 = (file) => {
    return new Promise((resolve) => {
      const fileReader = new FileReader()
      fileReader.readAsDataURL(file)
      fileReader.onload = (ev) => {
        resolve(ev.target.result);
      }
    })
  }

})();

// 缩略图上传
(function () {
  let upload3 = document.querySelector('#upload3'),
    upload_inp = upload3.querySelector('.upload_inp'),
    upload_btn_select = upload3.querySelector('.upload_btn.select'),
    upload_btn_upload = upload3.querySelector('.upload_btn.upload'),
    upload_abbre = upload3.querySelector('.upload_abbre'),
    upload_abbre_img = upload_abbre.querySelector('img');


  let _file = null

  const checkIsDisable = (element) => {
    const classlist = element.classList
    return classlist.contains('disabled')
  }

  // 把选择的文件读取为base64
  const readFileToBase64 = (file) => {
    return new Promise((resolve) => {
      const fileReader = new FileReader()
      fileReader.readAsDataURL(file)
      fileReader.onload = (ev) => {
        resolve(ev.target.result);
      }
    })
  }

  // 把选择的文件读取为buffer
  const readFileToBufferToHashCode = (file) => {
    return new Promise((resolve) => {
      const fileReader = new FileReader()
      fileReader.readAsArrayBuffer(file)
      fileReader.onload = (ev) => {
        // buffer
        const fileBuffer = ev.target.result
        // 生成 hash code
        const spark = new SparkMD5.ArrayBuffer()
        spark.append(fileBuffer)
        const hash = spark.end()
        const suffix = /\.([a-zA-Z0-9]+)$/.exec(file.name)[1]
        resolve({
          fileBuffer,
          hash,
          suffix,
          filename: `${hash}.${suffix}`
        });
      }
    })
  }

  const handleDisable = (flag) => {
    if (flag) {
      upload_btn_select.classList.add('disabled')
      upload_btn_upload.classList.add('disabled')
      return
    }
    upload_btn_select.classList.remove('disabled')
    upload_btn_upload.classList.remove('disabled')
  }

  // 点击选择文件按钮，触发上传文件input输入框
  upload_btn_select.addEventListener('click', function() {
    checkIsDisable(this)
    upload_inp.click()
  })

  // 监听用户选择文件的操作，并获取用户选择的文件
  upload_inp.addEventListener('change', async function() {
    const file = upload_inp.files[0]
    if (!file) return
    // 限制文件上传的格式
    if(!/PNG|JPG|JPEG/i.test(file.type)) {
      alert('只能上传PNG/JPG/JPEG格式的图片~')
      return
    }
    // 限制文件大小
    if (file.size > 2 * 1024 * 1024) {
      alert('图片大小不能超过2M~')
      return
    }
    handleDisable(true)
    // 文件预览， 就是把文件对象转换为base64，赋值给图片的src属性
    const base64 = await readFileToBase64(file)
    upload_abbre.style.display = 'block'
    upload_abbre_img.src = base64
    handleDisable(false)
    _file = file
  })

  // 上传到服务器
  upload_btn_upload.addEventListener('click', async function() {
    if (!_file) {
      alert('请选择上传的文件')
      return
    }
    handleDisable(true) // 处理中禁用按钮

    // 生成文件hash名
    const { filename } = await readFileToBufferToHashCode(_file)

    // 上传 FormData
    let formData = new FormData()
    formData.append('file', _file)
    formData.append('filename', filename)

    instance.post('/upload_single_name', formData)
    .then(data => {
      console.log(data)
      if (+data.code === 0) {
        alert(`文件上传成功，可以使用 ${data.servicePath} 访问这个资源~`)
        return
      }
      return Promise.reject(data.codeText)
    }).catch(reason => {
      alert('文件上传失败，清稍后重试~' + reason)
    }).finally(() => {
      handleDisable(false)
      upload_abbre.style.display = 'none'
      upload_abbre_img.src = ''
      _file = null
    })
  })
})();

// 进度管控
(function () {
  let upload4 = document.querySelector('#upload4'),
    upload_inp = upload4.querySelector('.upload_inp'),
    upload_btn_select = upload4.querySelector('.upload_btn.select'),
    upload_progress = upload4.querySelector('.upload_progress'),
    upload_progress_value = upload_progress.querySelector('.value');


  const checkIsDisable = (element) => {
    const classlist = element.classList
    return classlist.contains('disabled')
  }

  // 点击选择文件按钮，触发上传文件input输入框
  upload_btn_select.addEventListener('click', function() {
    checkIsDisable(this)
    upload_inp.click()
  })


  // 监听用户选择文件的操作，并获取用户选择的文件
  upload_inp.addEventListener('change', async function() {
    const file = upload_inp.files[0]
    if (!file) return
    // 限制文件上传的格式
    if(!/PNG|JPG|JPEG/i.test(file.type)) {
      alert('只能上传PNG/JPG/JPEG格式的图片~')
      return
    }
    // 限制文件大小
    if (file.size > 20 * 1024 * 1024) {
      alert('图片大小不能超过2M~')
      return
    }
    upload_btn_select.classList.add('disabled')

    try {
      const formData = new FormData()
      formData.append('file', file)
      formData.append('filename', file.name)
      const data = await instance.post('/upload_single', formData, {
        onUploadProgress(ev) { // axios 提供的上传进度回调函数
          const { loaded, total } = ev
          console.log(loaded/total*100);
          upload_progress.style.display = 'block'
          upload_progress_value.style.width = `${loaded/total*100}%`
        }
      })
      if (+data.code === 0) {
        upload_progress_value.style.width = `100%`
        await delay(300)
        alert(`文件上传成功，可以使用 ${data.servicePath} 访问这个资源~`)
        return
      }
      throw data.codeText
    } catch (error) {
      alert('上传失败：' + error)
    } finally {
      upload_btn_select.classList.remove('disabled')
      upload_progress.style.display = 'none'
      upload_progress_value.style.width = `0%`
    }

  })
})();

// 多文件上传
(function () {
  let upload5 = document.querySelector('#upload5'),
    upload_inp = upload5.querySelector('.upload_inp'),
    upload_btn_select = upload5.querySelector('.upload_btn.select'),
    upload_btn_upload = upload5.querySelector('.upload_btn.upload'),
    upload_list = upload5.querySelector('.upload_list');
  let _files = []

  const checkIsDisable = (element) => {
    const classlist = element.classList
    return classlist.contains('disabled')
  }


  const handleDisable = (flag) => {
    if (flag) {
      upload_btn_select.classList.add('disabled')
      upload_btn_upload.classList.add('disabled')
      return
    }
    upload_btn_select.classList.remove('disabled')
    upload_btn_upload.classList.remove('disabled')
  }

  // 获取唯一值
  const createRandom = () => {
    const ran = Math.random() * new Date()
    return ran.toString(16).replace('.', '')
  }

  // 点击选择文件按钮，触发上传文件input输入框
  upload_btn_select.addEventListener('click', function() {
    checkIsDisable(this)
    upload_inp.click()
  })

  // 监听用户选择文件的操作，并获取用户选择的文件
  upload_inp.addEventListener('change', async function() {
    _files = Array.from(upload_inp.files)
    if (_files.length === 0) {
      return
    }
    console.log(_files);
    _files = _files.map(file => {
      return {
        file,
        filename: file.name,
        key: createRandom()
      }
    })
    let str = ''
    _files.forEach((item, index) => {
      str += `
      <li key='${item.key}'>
        <span>文件${index+1}：${item.filename}</span>
        <span><em>移除</em></span>
      </li>
      `
    })
    upload_list.style.display = 'block'
    upload_list.innerHTML = str
    // 删除
    upload_list.addEventListener('click', function(e) {
      if (e.target.tagName === 'EM') {
        const curLi = e.target.parentNode.parentNode
        if (!curLi) return
        upload_list.removeChild(curLi)
        const key = curLi.getAttribute('key')
        _files = _files.filter(item => item.key !== key)
        if (!_files.length) {
          upload_list.style.display = 'none'
          upload_list.innerHTML = ''
        }
      }
    })
  })

  // 上传到服务器
  upload_btn_upload.addEventListener('click', async function() {
    if (!_files.length) {
      alert('请选择上传的文件')
      return
    }
    handleDisable(true) // 处理中禁用按钮
    // 给每个li设置进度
    // 获取li
    const upload_list_li = Array.from(upload_list.querySelectorAll('li'))

    const reqLists = _files.map(item => {
      const fm = new FormData()
      fm.append('file', item.file)
      fm.append('filename', item.filename)
      const curLi = upload_list_li.find(li => li.getAttribute('key') === item.key)
      const curSpan = curLi ? curLi.querySelector('span:nth-last-child(1)') : null
      return instance.post('upload_single', fm, {
        onUploadProgress(ev) {
          // 检测每一个的上传进度
          const percent = `${(ev.loaded/ev.total * 100).toFixed(2)}%`
          if (curSpan) {
            curSpan.innerHTML = percent
          }
        }
      }).then(data => {
        if (+data.code === 0) {
          if (curSpan) {
            curSpan.innerHTML = '100%'
          }
         return
        }
        return Promise.reject('')
      })
    })

    Promise.all(reqLists).then(() => {
      alert('文件上传成功')
    }).catch(() => {
      alert('文件上传失败')
    }).finally(() => {
      handleDisable(false)
      upload_list.style.display = 'none'
      upload_list.innerHTML = ''
    })
  })
})();

// 拖拽上传
(function () {
  let upload6 = document.querySelector('#upload6'),
  upload_inp = upload6.querySelector('.upload_inp'),
  // upload_drag = upload6.querySelector('.upload_drag'),
  upload_submit = upload6.querySelector('.upload_submit'),
  upload_mark = upload6.querySelector('.upload_mark');

  let isRun = false


  // 文件上传
  const upload = async (file) => {
    if (isRun) {
      return
    }
    isRun = true
    upload_mark.style.display = 'flex'
    try {
      const fm = new FormData()
      fm.append('file', file)
      fm.append('filename', file.name)
      const data = await instance.post('upload_single', fm)
      if (+data.code === 0) {
        alert(`文件上传成功，可以使用 ${data.servicePath} 访问这个资源~`)
        return
      }
      throw data.codeText
    } catch (error) {
      alert('文件上传失败' + error)
    } finally {
      upload_mark.style.display = 'none'
      isRun = false
    }
  }

  // 点击选择文件按钮，触发上传文件input输入框
  upload_submit.addEventListener('click', function() {
    // checkIsDisable(this)
    upload_inp.click()
  })

  // 手动上传 -- 监听用户选择文件的操作，并获取用户选择的文件
  upload_inp.addEventListener('change', async function() {
    const file = upload_inp.files[0]
    if (!file) {
      return
    }
    // console.log(file);
    upload(file)
  })
  // 拖拽上传 dragenter dragleave dragover drop
  // upload6.addEventListener('dragenter', function () {
  //   console.log('进入')
  // })

  upload6.addEventListener('dragover', function (e) {
    e.preventDefault()
    // console.log('dragover 区域内移动')
  })

  upload6.addEventListener('drop', function (e) {
    e.preventDefault()
    // console.log('drop 放下文件')
    const file = e.dataTransfer.files[0]
    if (!file) return
    // console.log('file', file);
    upload(file)
  })

  // upload6.addEventListener('dragleave', function () {
  //   console.log('离开')
  // })
})();

// 大文件上传
(function () {
  let upload7 = document.querySelector('#upload7'),
    upload_inp = upload7.querySelector('.upload_inp'),
    upload_btn_select = upload7.querySelector('.upload_btn.select'),
    upload_progress = upload7.querySelector('.upload_progress'),
    upload_progress_value = upload_progress.querySelector('.value');


  const checkIsDisable = (element) => {
    const classlist = element.classList
    return classlist.contains('disabled')
  }


  // 把选择的文件读取为buffer
  const readFileToBufferToHashCode = (file) => {
    return new Promise((resolve) => {
      const fileReader = new FileReader()
      fileReader.readAsArrayBuffer(file)
      fileReader.onload = (ev) => {
        // buffer
        const fileBuffer = ev.target.result
        // 生成 hash code
        const spark = new SparkMD5.ArrayBuffer()
        spark.append(fileBuffer)
        const hash = spark.end()
        const suffix = /\.([a-zA-Z0-9]+)$/.exec(file.name)[1]
        resolve({
          fileBuffer,
          hash,
          suffix,
          filename: `${hash}.${suffix}`
        });
      }
    })
  }

  // 点击选择文件按钮，触发上传文件input输入框
  upload_btn_select.addEventListener('click', function() {
    checkIsDisable(this)
    upload_inp.click()
  })

  // 监听用户选择文件的操作，并获取用户选择的文件
  upload_inp.addEventListener('change', async function() {
    const file = upload_inp.files[0]
    if (!file) return
    // 限制文件上传的格式
    if(!/PNG|JPG|JPEG/i.test(file.type)) {
      alert('只能上传PNG/JPG/JPEG格式的图片~')
      return
    }
    // 限制文件大小
    if (file.size > 20 * 1024 * 1024) {
      alert('图片大小不能超过2M~')
      return
    }
    upload_btn_select.classList.add('disabled')
    upload_progress.style.display = 'block'

    // 获取文件的hash
    const { hash, suffix } = await readFileToBufferToHashCode(file)
    // 已经上传成功的切片数组
    const already = await queryUploadedChunks(hash)
    // 切割文件生成的切片
    const { chunks, chunksTotal } = chunkFile(file, hash, suffix)

    // 上传切片
    uploadFiles(chunks, already, () => mergeChunk(hash, chunksTotal))


  })

  // 获取已经上传成功的切片 ['hash_1', 'hash_2']
  const queryUploadedChunks = async (hash) => {
    // 获取已经上传的切片
    try {
      const data = await instance.get('/upload_already', {
        params: {
          HASH: hash
        }
      })
      if (+data.code === 0) {
        return data.fileList
      }
    } catch (error) {

    }
  }

  // 切割文件
  const chunkFile = (file, hash, suffix) => {
    // 实现文件切片处理 固定大小 固定数量
    let max = 1024 * 100,
        count = Math.ceil(file.size / max),
        index = 0,
        chunks = [];
    if (count > 100) {
      max = file.size / 100
      count = 100
    }

    // 使用 file 中提供的 slice 方法实现切割
    while (index < count) {
      chunks.push({
        file: file.slice(index * max, (index + 1) * max),
        filename: `${hash}_${index + 1}.${suffix}`
      })
      index++
    }

    return {
      chunks,
      chunkSize: max,
      chunksTotal: count
    }
  }

  // 上传文件
  const uploadFiles = (chunks, already=[], fn) => {
    chunks.forEach((chunk, index, arr) => {
      // 已经上传过的切片
      if (already.length && already.includes(chunk.filename)) {
        complete(index+1, arr.length, fn) // 展示完成状态
        return
      }
      const fm = new FormData()
      fm.append('file', chunk.file)
      fm.append('filename', chunk.filename)
      console.log('fm', fm)
      // 上传每个切片
      instance.post('/upload_chunk', fm).then(data => {
        if (+data.code === 0) {
          complete(index+1, arr.length, fn)
          return
        }
      }).catch(() => {
        alert('当前切片上传失败，请稍后再试~')
        clear()
      })
    })
  }
  // 上传成功处理
  const complete = (curUploadIndex, count, fn) => {
    // 管控进度条
    upload_progress_value.style.width = `${curUploadIndex/count*100}%`
    if (curUploadIndex < count) return
    // 所有切片都上传成功
    upload_progress_value.style.width = '100%'
    fn()
  }

  // 合并切片
  const mergeChunk = async (hash, count) => {
    console.log('mergeChunk', mergeChunk);
    try {
      const data = await instance.post('upload_merge', {
        HASH: hash,
        count
      }, {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        }
      })
      if (+data.code === 0) {
        alert(`文件上传成功，可以使用 ${data.servicePath} 访问这个资源~`)
        clear()
        return
      }
      throw data.codeText
    } catch (error) {
      alert('合并切片失败，请稍后再试')
      clear()
    }
  }
  //
  const clear = () => {
    upload_btn_select.classList.add('disabled')
    upload_progress.style.display = 'block'
    upload_progress_value.style.width = '0%'
  }
})();
// alert(`文件上传成功，可以使用 ${data.servicePath} 访问这个资源~`)
